package gbackup.command;


import gbackup.core.RemoteFile;
import gbackup.core.Shell;
import gbackup.core.Utility;

import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.google.gdata.client.media.ResumableGDataFileUploader;
import com.google.gdata.client.uploader.ProgressListener;
import com.google.gdata.client.uploader.ResumableHttpFileUploader;
import com.google.gdata.data.MediaContent;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.docs.DocumentListEntry;
import com.google.gdata.data.docs.FileEntry;
import com.google.gdata.data.media.MediaFileSource;
import com.google.gdata.util.ServiceException;


public class PutCommand extends Command {

	public PutCommand(Shell shell, String rawCommand) {
		super(shell, rawCommand);
	}

	@Override
	public void execute() {
		if (this._arguments.size() != 1) {
			this._outputPrintStream.println("Invalid Argument : [" + this._rawCommand + "]");
			return;
		}

		java.io.File sourceFile = new java.io.File(this._shell.getLocalWorkingDirectory().getAbsoluteFile() + RemoteFile.pathSeperator + this._arguments.get(0));
		if (!sourceFile.exists()) {
			this._outputPrintStream.println("Not Such File : [" + this._arguments.get(0) + "]");
			return;
		}

		String destFolderUrl = ((MediaContent) this._shell.getRemoteWorkingDirectory().getEntry().getContent()).getUri();

		try {
			java.io.File zipedFile = Utility.zip(sourceFile);
			DocumentListEntry entry = this.uploadFile(zipedFile, destFolderUrl);
			this._shell.getDocsService().insert(new URL(destFolderUrl), entry);

			String allContentInFolder = "https://docs.google.com/feeds/default/private/full/" + this._shell.getRemoteWorkingDirectory().getEntry().getResourceId() + "/contents";
			DocumentListEntry updatedEntry = null;
			for (DocumentListEntry e : Utility.getDocumentListFeedByURL(this._shell.getDocsService(), allContentInFolder).getEntries()) {
				if (!e.getTitle().getPlainText().equals(entry.getTitle().getPlainText()))
					continue;
				updatedEntry = e;
			}
			if (updatedEntry == null)
				new RuntimeException("Should be impossible");
			updatedEntry.setTitle(new PlainTextConstruct(sourceFile.getName() + ".zip"));
			updatedEntry.update();

			RemoteFile newFile = new RemoteFile(this._shell.getRemoteWorkingDirectory(), updatedEntry);
			this._shell.getRemoteWorkingDirectory().addChild(newFile);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public DocumentListEntry uploadFile(java.io.File sourceFile, String destFolderUrl) throws IOException, ServiceException {
		FileEntry newFile = new FileEntry();
		String mimeType = DocumentListEntry.MediaType.fromFileName(sourceFile.getName()).getMimeType();
		myProgressListener listener = new myProgressListener();
		ExecutorService executor = Executors.newFixedThreadPool(10);
		MediaFileSource mediaFile = new MediaFileSource(sourceFile, mimeType);

		URL createUploadUrl = new URL("https://docs.google.com/feeds/upload/create-session/default/private/full");
		ResumableGDataFileUploader uploader = new ResumableGDataFileUploader.Builder(this._shell.getDocsService(), createUploadUrl, mediaFile, newFile).title(sourceFile.getName())
				.chunkSize(ResumableGDataFileUploader.DEFAULT_MAX_CHUNK_SIZE).executor(executor).trackProgress(listener, ResumableGDataFileUploader.DEFAULT_PROGRESS_INTERVAL_MS).build();

		uploader.start();

		while (!listener.isDone()) {
			try {
				Thread.sleep(500);
				this._outputPrintStream.print(".");
			} catch (InterruptedException ie) {
				ie.printStackTrace();
			}
		}
		this._outputPrintStream.println();

		return uploader.getResponse(DocumentListEntry.class);
	}

	private class myProgressListener implements ProgressListener {

		private ResumableHttpFileUploader _uploader = null;

		@Override
		public void progressChanged(ResumableHttpFileUploader arg0) {
			this._uploader = arg0;
		}

		public boolean isDone() {
			return this._uploader == null ? false : this._uploader.isDone();
		}
	}
}
